package com.author.surface;

import java.awt.Color;
import java.util.Hashtable;
import java.util.Set;
import java.util.Map.Entry;

import javax.swing.JSlider;
import javax.swing.text.StyleConstants;

import com.author.document.model.ExtendedDocument;
import com.author.document.style.StyleChangeNotify;

public final class UIupdater {
	/*
	 * The following table keeps a mapping between the property name and the
	 * button which is responsible for that property
	 */
	private static Hashtable<Object, Object>	ui_table	= new Hashtable<Object, Object>();

	/* Make the UI updater class singleton, only one instance will exist */
	private static boolean						IS_CREATED	= false;

	/* Reference to the UI updater object */
	private static UIupdater					UI_UPDATE	= null;

	private UIupdater() {
		if (!UIupdater.IS_CREATED) {
			UIupdater.IS_CREATED = true;
		}
	}

	public static UIupdater getUIupdater() {
		if (!UIupdater.IS_CREATED) {
			UIupdater.UI_UPDATE = new UIupdater();
			return UIupdater.UI_UPDATE;
		}
		return UIupdater.UI_UPDATE;
	}

	/**
	 * Put the name of the property and the button reference responsible for its
	 * maintenance in the ui table
	 */
	public void put(Object key, Object value) {
		ui_table.put(key, value);
	}

	/**
	 * @param key
	 *            , The key or the UI property to search for in the UI table
	 * @return The GUI widget responsible for maintaining the key
	 */
	public Object get(Object key) {
		if (!(UIupdater.ui_table.contains(key))) {
			return null;
		}

		return UIupdater.ui_table.get(key);
	}

	/**
	 * When the UI updater gets the table of UI properties from the Style
	 * Observer object it invokes the corresponding buttons which are
	 * responsible for the maintenance of that particular property
	 * 
	 * @param uiTable
	 *            , Table with the current UI properties
	 */
	public void update(Hashtable<Object, Object> uiTable) {
		if ((uiTable == null) || (uiTable.size() == 0)) return;

		/*
		 * Go through each and every item in the ui table, and ask the
		 * respective buttons which are responsible for the maintenance of that
		 * property if it (the button) needs to display a different state then
		 * the one it is currently displaying.
		 */
		Set<Entry<Object, Object>> set = uiTable.entrySet();
		for (Entry<Object, Object> e : set) {
			if (e.getKey() == StyleConstants.FontSize) {
				FontSizeComboBox cb = (FontSizeComboBox) ui_table
						.get(StyleChangeNotify.FONT_SIZE);
				cb.setFontSize((Integer) e.getValue());
				continue;
			}

			if (e.getKey() == StyleConstants.Bold) {
				BoldAction boldAction = (BoldAction) ui_table
						.get(StyleChangeNotify.BOLD);
				boldAction.setBold((Boolean) e.getValue());
				continue;
			}

			if (e.getKey() == StyleConstants.Italic) {
				ItalicAction italicAction = (ItalicAction) ui_table
						.get(StyleChangeNotify.ITALIC);
				italicAction.setItalic((Boolean) e.getValue());
				continue;
			}

			if (e.getKey() == StyleConstants.Underline) {
				UnderlineAction underlineAction = (UnderlineAction) ui_table
						.get(StyleChangeNotify.UNDERLINE);
				underlineAction.setUnderline((Boolean) e.getValue());
				continue;
			}

			if (e.getKey() == StyleConstants.Superscript) {
				SuperscriptAction superscriptAction = (SuperscriptAction) ui_table
						.get(StyleChangeNotify.SUPERSCRIPT);
				superscriptAction.setSuperscript((Boolean) e.getValue());
				continue;
			}

			if (e.getKey() == StyleConstants.Subscript) {
				SubscriptAction subscriptAction = (SubscriptAction) ui_table
						.get(StyleChangeNotify.SUBSCRIPT);
				subscriptAction.setSubscript((Boolean) e.getValue());
				continue;
			}

			if (e.getKey() == StyleConstants.Alignment) {
				int value = (Integer) e.getValue();
				AlignActionButtonGroup.AlignLeft alignLeftAction = (AlignActionButtonGroup.AlignLeft) ui_table
						.get(StyleChangeNotify.LEFT_ALIGN);
				AlignActionButtonGroup.AlignCenter alignCenterAction = (AlignActionButtonGroup.AlignCenter) ui_table
						.get(StyleChangeNotify.CENTER_ALIGN);
				AlignActionButtonGroup.AlignRight alignRightAction = (AlignActionButtonGroup.AlignRight) ui_table
						.get(StyleChangeNotify.RIGHT_ALIGN);
				AlignActionButtonGroup.AlignJustify alignJustifyAction = (AlignActionButtonGroup.AlignJustify) ui_table
						.get(StyleChangeNotify.JUSTIFY_ALIGN);

				/*
				 * Once an alignment button is made visible, all of its siblings
				 * are made invisible as only one alignment button can be on a
				 * true state at any point in the document.
				 */
				switch (value) {
				case StyleConstants.ALIGN_LEFT:
					alignLeftAction.setAlignmentLeft(true);
					alignCenterAction.setAlignmentCenter(false);
					alignRightAction.setAlignmentRight(false);
					alignJustifyAction.setAlignmentJustify(false);
					break;
				case StyleConstants.ALIGN_CENTER:
					alignLeftAction.setAlignmentLeft(false);
					alignCenterAction.setAlignmentCenter(true);
					alignRightAction.setAlignmentRight(false);
					alignJustifyAction.setAlignmentJustify(false);
					break;
				case StyleConstants.ALIGN_RIGHT:
					alignLeftAction.setAlignmentLeft(false);
					alignCenterAction.setAlignmentCenter(false);
					alignRightAction.setAlignmentRight(true);
					alignJustifyAction.setAlignmentJustify(false);
					break;
				case StyleConstants.ALIGN_JUSTIFIED:
					alignLeftAction.setAlignmentLeft(false);
					alignCenterAction.setAlignmentCenter(false);
					alignRightAction.setAlignmentRight(false);
					alignJustifyAction.setAlignmentJustify(true);
					break;
				default:
					break;
				}
			}

			if (e.getKey() == StyleConstants.LineSpacing) {
				Float value = (Float) e.getValue();
				float value2 = value.floatValue();

				LineSpacingButtonGroup.SingleSpace singlespaceAction = (LineSpacingButtonGroup.SingleSpace) ui_table
						.get(StyleChangeNotify.SINGLESPACE);
				LineSpacingButtonGroup.OneHalfSpace onehalfspaceAction = (LineSpacingButtonGroup.OneHalfSpace) ui_table
						.get(StyleChangeNotify.ONEHALFSPACE);
				LineSpacingButtonGroup.DoubleSpace doublespaceAction = (LineSpacingButtonGroup.DoubleSpace) ui_table
						.get(StyleChangeNotify.DOUBLESPACE);

				/*
				 * Once a line spacing button is made visible, all of its
				 * siblings are made invisible as only one line spacing button
				 * can be on a true state at any point in the document.
				 */
				if (value2 == LineSpacingButtonGroup.SingleSpace.SINGLE_SPACING) {
					singlespaceAction.setSingleLineSpace(true);
					onehalfspaceAction.setOneHalfLineSpace(false);
					doublespaceAction.setDoubleLineSpace(false);
				} else if (value2 == LineSpacingButtonGroup.OneHalfSpace.ONEHALF_SPACING) {
					singlespaceAction.setSingleLineSpace(false);
					onehalfspaceAction.setOneHalfLineSpace(true);
					doublespaceAction.setDoubleLineSpace(false);
				} else if (value2 == LineSpacingButtonGroup.DoubleSpace.DOUBLE_SPACING) {
					singlespaceAction.setSingleLineSpace(false);
					onehalfspaceAction.setOneHalfLineSpace(false);
					doublespaceAction.setDoubleLineSpace(true);
				}
			}

			if (e.getKey() == StyleConstants.Foreground) {
				ForegroundColorButton fgcolorBtn = (ForegroundColorButton) UIupdater.ui_table
						.get(StyleChangeNotify.FOREGROUND_COLOR);
				if (fgcolorBtn.getForegroundColor()
						.equals((Color) e.getValue())) {
					continue;
				} else {
					fgcolorBtn.setForegroundColor((Color) e.getValue());
				}
			}

			if (e.getKey() == StyleConstants.Background) {
				BackgroundColorButton bgcolorBtn = (BackgroundColorButton) UIupdater.ui_table
						.get(StyleChangeNotify.BACKGROUND_COLOR);
				if (bgcolorBtn.getBackgroundColor()
						.equals((Color) e.getValue())) {
					continue;
				} else {
					bgcolorBtn.setBackgroundColor((Color) e.getValue());
				}
			}
		}
	}

	/**
	 * Update the UI with paragraph attributes. This will primarily affect the
	 * position of the JSlider
	 * 
	 * @param uiTable
	 *            - Table with the current UI properties of paragraphs
	 */
	public void update2(Hashtable<Object, Object> uiTable) {
		if ((uiTable == null) || (uiTable.size() == 0)) {
			return;
		}

		/* The same logic is applied here, as can be found in method update */
		Set<Entry<Object, Object>> set = uiTable.entrySet();
		for (Entry<Object, Object> e : set) {
			if (e.getKey() == ExtendedDocument.PARAGRAPH_LEFT_INDENT) {
				JSlider slider = TextPanel.getSlider();
				if (slider == null) {
					continue;
				}

				Integer value = (Integer) e.getValue();
				if (value == null) {
					continue;
				}

				if ((value < CustomSlider.SLIDER_INITIAL_POSITION)
						|| (value > CustomSlider.SLIDER_FINAL_POSITION)) {
					value = CustomSlider.SLIDER_INITIAL_POSITION;
				}

				((CustomSlider) slider).setChangeEventResponse(false);
				slider.setValue(value);
				continue;
			}
		}
	}
}
